[Day19]我們成功透過Streamlit
建立了config
檔,並儲存於本機端。但是當我們想要將此config
分享給其他人,又或者想要於其他電腦使用這個config
,該怎麼做呢?
我們的作法是放在一個自己可控制的下載空間,Linode Object Storage(S3-compatible)是我們推薦的解決方案。
Linode
中建立一個名為ithome2022-st-s3
的Bucket
,地點選擇ap-south-1
的新加坡,此Bucket
的網址為ithome2022-st-s3.ap-south-1.linodeobjects.com
。Bucket
,建立一組aws_access_key_id
及aws_secret_access_key
並將其輸入至.streamlit/secrets.toml
。另外再建立endpoint_url = "https://ap-south-1.linodeobjects.com"
及bucket_name = "ithome2022-st-s3"
兩個secret
。整個.streamlit/secrets.toml
看起來會像是:
aws_access_key_id = "0aa818b68c0145c38ac6" # fake
aws_secret_access_key = "30427f2bab4b4d87993f78c6e6911a885417c4ab" # fake
endpoint_url = "https://ap-south-1.linodeobjects.com"
bucket_name = "ithome2022-st-s3"
st.secrets
當作一個字典,透過它取得儲存於.streamlit/secrets.toml
的secrets
。pydantic
建立一個S3Credentials model
將這些secret
存為一個pydantic model
。MyS3
來呼叫boto3
產生client
,供後續Streamlit
使用。get_my_s3
, 將S3Credentials
傳給MyS3
後回傳。#st_app.py
import boto3
import streamlit as st
from pydantic import BaseModel
class S3Credentials(BaseModel):
aws_access_key_id: str
aws_secret_access_key: str
endpoint_url: str
class MyS3:
def __init__(self, s3_credentials):
self.s3_credentials = s3_credentials
def get_s3_client(self):
if hasattr(self, 's3_client'):
return self.s3_client
self.s3_client = boto3.client('s3', **self.s3_credentials)
return self.s3_client
def get_my_s3():
s3_credentials = S3Credentials(aws_access_key_id=st.secrets['aws_access_key_id'],
aws_secret_access_key=st.secrets['aws_secret_access_key'],
endpoint_url=st.secrets['endpoint_url'])
return MyS3(s3_credentials=s3_credentials.dict())
get_my_s3
及其get_s3_client function
取得s3_client
。json.dumps
寫出data
並進行'utf-8'
的encoding
後放入BytesIO
。請注意,這邊需要做s.seek(0)
,可參考stackoverflow的文章。boto3.client
的upload_fileobj function
,將config
上傳至Linode Object Storage
。關於權限部份,我們於ExtraArgs
將ACL
設定為public-read
(預設是private
),這樣就可以供每個人下載了。#st_app.py
bucket_name = st.secrets['bucket_name']
my_s3 = get_my_s3()
s3_client = my_s3.get_s3_client()
s = BytesIO(json.dumps(data).encode('utf-8'))
s.seek(0)
filename = 'input_data.json'
s3_client.upload_fileobj(Fileobj=s,
Bucket=st.secrets['bucket_name'],
Key=filename,
ExtraArgs={'ACL': 'public-read'})
now = datetime.now().strftime('%Y%m%d_%H%M%s')
st.info(
f'{filename} is uploaded to Bucket[{bucket_name}] at {now}.')
Streamlit Cloud 現在為一免費部署服務,其限制如下:
Services | Limits |
---|---|
Resources per app | 1 GB |
Private apps | 1 app |
Public apps | Unlimited |
Users | 3 users |
我們選擇用GitHub Account
來註冊Streamlit
,如果日後要部署Private App
會比較方便。
在部署之前,我們可以利用streamlit Cloud
的secrets management
來製造一個需要登入username
及password
,才能使用App
的入口。
Streamlit
很貼心地提供了可以複製貼上的check_password function。有了這個function
後,我們可以在一進入App
,就先檢查username
及password
,如果正確才會顯示出Form
。
#st_app.py
def check_password():
...
def main():
if check_password():
...
加上原先位於.streamlit/secrets.toml
的四個環境變數,我們的App Settings
中的Secrets
欄位會看起來像:
aws_access_key_id = "0aa818b68c0145c38ac6" # fake
aws_secret_access_key = "30427f2bab4b4d87993f78c6e6911a885417c4ab" # fake
endpoint_url = "https://ap-south-1.linodeobjects.com"
bucket_name = "ithome2022-st-s3"
[passwords]
"jrycw@example.com" = "ithome2022" # fake
這樣一來,我們部署於Streamlit Cloud
就不再需要依靠.streamlit/secrets.toml
這個檔案來提供secrets了。
我們選擇Public apps
,其部署介面如下:
部署過程或部署完畢後,可以點選右下角的Manage app
觀看log或做更多操控。
例如可以點選Analytics
,觀看Streamlit Cloud
提供的統計分析(此為示意圖,非本app真實數據):
此處我們新建一個env.py
來儲存s3_url
,並透過urllib
去讀入config
檔,並傳給main
。
請注意,如果遇到如[Day02 安裝VSCode]的問題,可以加上ssl._create_default_https_context = ssl._create_unverified_context
來解決(後果請自行評估...)。
#box_drop.py
ssl._create_default_https_context = ssl._create_unverified_context
with urllib.request.urlopen(s3_url) as resp:
config = json.load(resp)
main(config)
我們將[Day08]的精進大綱稍微更動,將原先預計於[Day20]~[Day21]濃縮於今天,原因是我們決定於明天分享如何使用Streamlit
來搭配Prefect
,請大家拭目以待。